package switchviz.graphic.gauge.graph2d;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import javax.media.opengl.GL;
import javax.swing.JPanel;

import org.jdom.Element;

import switchviz.graphic.gauge.GaugeDataModel;
import switchviz.graphic.gauge.IGauge;
import switchviz.graphic.gauge.graph2d.scale.Graph2dBoard;

public class Graph2d extends IGauge {
	
	private class Data
	{
		public float lastpoint = 0.0f;
		public Queue<Float> list = new LinkedList<Float>();
		private int size, granularity, count=0;
		
		public Data(int size, int granularity)
		{
			this.size = size;
			this.granularity = granularity;
		}
		
		public void add(float value)
		{
			if (count == 0)
			{
				list.add(lastpoint);
				
				if (list.size()>size)
					list.poll();
			}
			count = ++count % granularity;
			
			lastpoint = value;
		}
	}
	
	private Graph2dBoard _scale = null;
	private Graph2dDataModel _graphmodel = null;
	private Graph2dPanel _panel = null;
	private Graph2dPersistence _nodehandler = null;
	
	private Data[] _lists;
	private float[][] _color;
	private boolean freeze = false;
	private boolean _enable = true;
	
	public Graph2d(String type, Element node)
	{
		super(type, node);
		
		init();
		
		if(getVisibleSignals() != null)
		{
			_lists = new Data[getVisibleSignals().length];
			for (int i = 0; i < getVisibleSignals().length; ++i)
			{
				_lists[i] = new Data(_graphmodel.getDataLength(), _graphmodel.getGranularity());
			}
		}
	}
	
	private void init()
	{
		_nodehandler = new Graph2dPersistence(_root);
		
		_graphmodel = _nodehandler.getDataModel();
		
		_scale = new Graph2dBoard(_nodehandler.getScaleElement(), _graphmodel.getScaleMode(), (int)_graphmodel.getDataMin(), (int)_graphmodel.getDataMax(), _enable);
	}
	
	public void initialize(GL gl) 
	{
		_scale.initialize(gl);
		
		if(getVisibleSignals() != null && getVisibleSignals().length > 0)
		{
			_color = new float[getVisibleSignals().length][3];
			for(int i = 0; i < getVisibleSignals().length; ++i)
			{
				_color[i] = getVisibleSignals()[i].getColor();
			}
				
		}
	}
	
	private void updateSignal()
	{
		if(!freeze && getVisibleSignals() != null)
			for (int i=0; i<getVisibleSignals().length; i++)
			{
				if(_lists.length == 0) 
					return;	
				
				_lists[i].add(getVisibleSignals()[i].getValue());
			}
	}
	
	public void draw(GL gl) 
	{
		_scale.draw(gl);
		
		if(!_enable) 
			return;
		
		gl.glTranslatef(-1.0f, -1.0f, 0.0f);
		gl.glScalef(2.0f, 2.0f, 0.0f);
		
		
		float steps = 1.0f/_graphmodel.getDataLength();
		
		gl.glPointSize(_graphmodel.getPointsize());
		
		for (int i=0; i<_lists.length; i++)
		{
			gl.glColor3f(_color[i][0], _color[i][1], _color[i][2]);
			float point=0.0f;
			
			if (_lists[i].lastpoint < _graphmodel.getDataMin())
			{
				point = -0.02f - (i*0.02f);
			}
			else if (_lists[i].lastpoint > _graphmodel.getDataMax())
			{
				point = 1.02f + (i*0.02f);
			}
			else
			{
				point = (_lists[i].lastpoint-_graphmodel.getDataMin())/(_graphmodel.getDataMax()-_graphmodel.getDataMin());
			}
			
			gl.glBegin(GL.GL_TRIANGLES);
			
			gl.glVertex2f(1.02f, point+0.03f);
			gl.glVertex2f(1.02f, point-0.03f);
			gl.glVertex2f(0.98f, point);
			
			gl.glEnd();
			
			int c=_graphmodel.getDataLength()-_lists[i].list.size();
			
			gl.glBegin(GL.GL_POINTS);
			
			Iterator<Float> iter = _lists[i].list.iterator();
			
			while (iter.hasNext())
			{
				float value = iter.next();
				
				if (value < _graphmodel.getDataMin())
				{
					
				}
				else if (value > _graphmodel.getDataMax())
				{
					
				}
				else
				{
					gl.glVertex2f(c*steps, (value-_graphmodel.getDataMin())/(_graphmodel.getDataMax()-_graphmodel.getDataMin()));
				}
				
				c++;
			}

			gl.glEnd();
		}
		
		updateSignal();
	}

	public void setElement(Element node) 
	{
		_root = node;
		
		init();
	}

	public void addSetupPanels(List<JPanel> panellist) 
	{
		panellist.add(getGraphPanel());
		panellist.add(_scale.getSetupPanel());
	}

	public void saveSetupPanels() 
	{
		_nodehandler.setElement(getGraphPanel().getElement());
		
		Element _scalenode = _scale.getElement();
		_nodehandler.getElement().removeContent(_nodehandler.getElement().getChild(Graph2dPersistence.SCALE));
		_nodehandler.getElement().addContent(_scalenode);
		
		_root = _nodehandler.getElement();
		
		init();
	}
	
	private Graph2dPanel getGraphPanel()
	{
		if (_panel == null)
			_panel = new Graph2dPanel(_nodehandler.getElement());
		
		return _panel;
	}
	
	public GaugeDataModel getGaugeDataModel() 
	{
		return _graphmodel;
	}

	@Override
	public void setEnable(boolean enable) 
	{
		_enable = enable;
		
		init();
	}

	@Override
	public void setDetailLevel(int level) {}

	@Override
	public void resetData() 
	{
		if(getVisibleSignals() != null)
		{
			_lists = new Data[getVisibleSignals().length];
			for (int i = 0; i < getVisibleSignals().length; ++i)
			{
				_lists[i] = new Data(_graphmodel.getDataLength(), _graphmodel.getGranularity());
			}
		}
	}

	@Override
	public void setFreeze(boolean b) 
	{
		freeze = b;
	}
}
